#include <inc/types.h>
#include <inc/vmcb.h>

#define EFER_SVME 0x1000

struct generl_regs
{
	uint64_t gregs[15];
}__attribute__ ((packed));

typedef union 
{
	uint64_t space[1024];
	struct generl_regs gregs;
}__attribute__ ((packed)) vm_frame;



static uint8_t iopm[4096*3] __attribute__((aligned (4096), section (".data")));
static uint8_t msrpm[4096*16] __attribute__((aligned (4096), section (".data")));

void svm_run(void);
void start_svm(void);
void rest_stack_run_svm(struct vmcb *vmcb, vm_frame *vfrm1);
void svm_exit_handler(void);
void msr_inter(void *pm, uint32_t msr, uint32_t acc);




static inline void svm_vmload(void *vmcb)
{
	__asm__ __volatile__ (".byte 0x0f, 0x01, 0xda"
								 : :"a"(vmcb):"memory");
}

static inline void svm_vmsave(void *vmcb)
{
	__asm__ __volatile__ (".byte 0x0f, 0x01, 0xdb"
								 : :"a"(vmcb):"memory");
}

static void svm_vmcb_init(struct vmcb *vmcb)
{
	/*Intercept cr0 write not read for notifying the hypervisor os'mode */
	vmcb->cr_intercepts = 0;//CR_INTERCEPT_CR0_WRITE;

	/*No DR intercepts*/
	vmcb->dr_intercepts = 0;

	/*No exception intercpet*/
	vmcb->exc_intercepts = 0;//0xffffffff;
	
	/*general intercepts*/
	vmcb->intercepts2 = INTERCEPT_VMRUN
		| INTERCEPT_VMCALL
		| INTERCEPT_VMLOAD
		| INTERCEPT_VMSAVE
		| INTERCEPT_STGI
		| INTERCEPT_CLGI;

	vmcb->tsc_offset = 0;
	vmcb->cpl = 0;

	/**/
	vmcb->efer = EFER_SVME;
	vmcb->tlb_control = 0;
	vmcb->guest_asid = 1;
	vmcb->np_enable = 0;
	vmcb->n_cr3 = 0;
	vmcb->lbr_virtual = 0;
	vmcb->intr_t.intr_masking = 0;

	vmcb->iopm_base_pa = (uint64_t)iopm;
	vmcb->msrpm_base_pa = (uint64_t)msrpm;

	vmcb->es.sel = 0x4000;
	vmcb->cs.sel = 0x4000;
	vmcb->ss.sel = 0x4000;
	vmcb->ds.sel = 0x4000;
	vmcb->fs.sel = 0x4000;
	vmcb->gs.sel = 0x4000;

	vmcb->es.attrib = 0x8a;
	vmcb->ss.attrib = 0x8a;
	vmcb->ds.attrib = 0x8a;
	vmcb->fs.attrib = 0x8a;
	vmcb->gs.attrib = 0x8a;
	vmcb->cs.attrib = 0x93;

	vmcb->es.limit = 0xffff;
	vmcb->cs.limit = 0xffff;
	vmcb->ds.limit = 0xffff;
	vmcb->ss.limit = 0xffff;
	vmcb->fs.limit = 0xffff;
	vmcb->gs.limit = 0xffff;

	vmcb->es.base = 0x40000;
	vmcb->ss.base = 0x40000;
	vmcb->cs.base = 0x40000;
	vmcb->ds.base = 0x40000;
	vmcb->fs.base = 0x40000;
	vmcb->gs.base = 0x40000;

	vmcb->idtr.base = 0;
	vmcb->idtr.limit = 256*4 - 1;

	vmcb->gdtr.base = 0;
	vmcb->gdtr.limit = 0xffff;

	vmcb->ldtr.base = 0;
	vmcb->ldtr.sel = 0;
	vmcb->ldtr.limit = 0xffff;
	vmcb->ldtr.attrib = 0x82;

	vmcb->tr.attrib = 0x08b;
	vmcb->tr.base = 0;
	vmcb->tr.limit = 0xffff;
	vmcb->tr.sel = 0;
	

	vmcb->rip = 0x47;
	vmcb->rsp = 0x9000;
	
		
	/*16 bit not in 32 bit*/
	vmcb->cr0 = 0x60000010;
	vmcb->cr2 = 0;
	vmcb->cr3 = 0;
	vmcb->cr4 = 0;
}
